package cn.huiyunche.base.service.interfaces.impl;

import cn.huiyunche.base.service.interfaces.BAreaService;
import cn.huiyunche.base.service.interfaces.BCityFactorService;
import cn.huiyunche.base.service.mappers.BAreaMapper;
import cn.huiyunche.base.service.mappers.ext.BAreaViewMapper;
import cn.huiyunche.base.service.model.BArea;
import cn.huiyunche.base.service.model.BAreaExample;
import cn.huiyunche.base.service.vo.*;
import cn.huiyunche.tools.basic.exceptions.BusinessException;
import com.alibaba.fastjson.JSON;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

@Service
public class BAreaServiceImpl implements BAreaService {

    private static final Logger LOGGER = LoggerFactory.getLogger(BAreaServiceImpl.class);

    @Autowired
    private BAreaMapper bAreaMapper = null;

    @Autowired
    private BAreaViewMapper bAreaViewMapper = null;

    @Autowired
    private BCityFactorService bCityFactorService = null;

    private BAreaMapper getBAreaMapper() {
        return this.bAreaMapper;
    }

    public BAreaViewMapper getBAreaViewMapper() {
        return this.bAreaViewMapper;
    }

    public BCityFactorService getBCityFactorService() {
        return this.bCityFactorService;
    }

    public List<BArea> selectDistrictByCityCode(String cityCode) throws Exception {
        LOGGER.info("selectDistrictByCityCode service param : {}", cityCode);
        BAreaExample search = new BAreaExample();
        BAreaExample.Criteria areaSearch = search.createCriteria();
        areaSearch.andParentCodeEqualTo(cityCode);
        return this.getBAreaMapper().selectByExample(search);
    }

    /**
     * 根据省编码查询所属城市
     *
     * @param provinceCode 省编码
     * @return List<BArea>
     * @throws BusinessException
     */
    public List<BArea> selectCityByProvinceCode(String provinceCode) throws Exception {
        LOGGER.info("selectCityByProvinceCode service param : {}", provinceCode);
        try {
            BAreaExample search = new BAreaExample();
            BAreaExample.Criteria areaSearch = search.createCriteria();
            areaSearch.andParentCodeEqualTo(provinceCode);
            return this.getBAreaMapper().selectByExample(search);
        } catch (Exception e) {
            LOGGER.error("selectCityByProvinceCode service param : {}, error.", provinceCode, e);
            throw new BusinessException("根据省编码查询所属城市异常");
        }
    }

    /**
     * 根据省编码查询所属城市
     *
     * @param cityCode 城市编码
     * @return List<BArea>
     * @throws BusinessException
     */
    public List<BArea> selectCountyByCityCode(String cityCode) throws Exception {
        LOGGER.info("selectCountyByCityCode service param : {}", cityCode);
        try {
            BAreaExample search = new BAreaExample();
            BAreaExample.Criteria areaSearch = search.createCriteria();
            areaSearch.andParentCodeEqualTo(cityCode);
            return this.getBAreaMapper().selectByExample(search);
        } catch (Exception e) {
            LOGGER.error("selectCityByProvinceCode service param : {}, error.", cityCode, e);
            throw new BusinessException("根据市编码查询所属区县异常");
        }
    }

    public List<BArea> selectProvinceList() throws Exception {
        BAreaExample search = new BAreaExample();
        BAreaExample.Criteria areaSearch = search.createCriteria();
        areaSearch.andLevelEqualTo("1");
        areaSearch.andIsTransportEqualTo(true);
        return this.getBAreaMapper().selectByExample(search);
    }

    @Override
    public List<BProvinceVo> selectProvinces() throws Exception {
        List<BArea> list = this.selectProvinceList();
        List<BProvinceVo> provinceVos = new ArrayList<>();
        for (BArea area : list) {
            BProvinceVo provinceVo = new BProvinceVo();
            provinceVo.setProvinceCode(area.getCode());
            provinceVo.setProvinceName(area.getName());
            provinceVos.add(provinceVo);
        }
        return provinceVos;
    }

    public List<BArea> selectAreaByParentCode(String parentCode) throws Exception {
        LOGGER.info("selectAreaByParentCode service param : {}", parentCode);
        BAreaExample search = new BAreaExample();
        BAreaExample.Criteria areaSearch = search.createCriteria();
        areaSearch.andParentCodeEqualTo(parentCode);
        return this.getBAreaMapper().selectByExample(search);
    }

    public List<BArea> selectAreaByCode(String code) throws Exception {
        LOGGER.info("selectAreaByCode service param : {}", code);
        BAreaExample search = new BAreaExample();
        BAreaExample.Criteria areaSearch = search.createCriteria();
        areaSearch.andCodeEqualTo(code);
        return this.getBAreaMapper().selectByExample(search);
    }

    public List<BArea> selectArea() throws Exception {
        BAreaExample search = new BAreaExample();
        return this.getBAreaMapper().selectByExample(search);
    }

    public List<ProvinceVo> selectAllArea() throws Exception {
        BAreaExample search = new BAreaExample();
        List<BArea> allList = this.getBAreaMapper().selectByExample(search);
        List<ProvinceVo> provinceList = new ArrayList<ProvinceVo>();
        List<CityVo> cityList = null;
        List<CityVo> cityLists = new ArrayList<CityVo>();
        // List<CountyVo> countyList = null;
        for (BArea area : allList) {
            if ("1".equals(area.getLevel())) {
                ProvinceVo pVo = new ProvinceVo();
                pVo.setProvinceCode(area.getCode());
                pVo.setProvinceName(area.getName());
                provinceList.add(pVo);
            }
        }
        for (ProvinceVo provinceVo : provinceList) {
            cityList = new ArrayList<CityVo>();
            for (BArea area : allList) {
                if (provinceVo.getProvinceCode().equals(area.getParentCode())) {
                    CityVo cVo = new CityVo();
                    cVo.setCityCode(area.getCode());
                    cVo.setCityName(area.getName());
                    cityList.add(cVo);
                    cityLists.add(cVo);
                }
            }
            provinceVo.setCityList(cityList);
        }
        // for (CityVo cityVo : cityLists) {
        // countyList = new ArrayList<CountyVo>();
        // for (Area area : allList) {
        // if (cityVo.getCityCode().equals(area.getParentCode())) {
        // CountyVo cVo = new CountyVo();
        // cVo.setCountyCode(area.getCode());
        // cVo.setCountyName(area.getName());
        // cVo.setLevel(area.getLevel());
        // cVo.setParentCode(area.getParentCode());
        // cVo.setComment(area.getComment());
        // cVo.setSort(area.getSort());
        // cVo.setPinyin(area.getPinyin());
        // countyList.add(cVo);
        // }
        // }
        // cityVo.setCountyList(countyList);
        // }
        return provinceList;
    }

    @Override
    public String getFullByCode(String code) {
        LOGGER.info("getFullByCode param : {}", code);
        if (StringUtils.isBlank(code)) {
            LOGGER.error("getFullByCode code must not be null");
            throw new BusinessException("编码不能为空！");
        }
        List<String> result = new ArrayList<>();
        return this.test(result, code);
    }

    public String test(List<String> result, String code) {
        if (StringUtils.isNotBlank(code)) {
            BAreaExample example = new BAreaExample();
            example.createCriteria().andCodeEqualTo(code);
            List<BArea> list = bAreaMapper.selectByExample(example);
            if (CollectionUtils.isNotEmpty(list)) {
                result.add(list.get(0).getName());
                return test(result, list.get(0).getParentCode());
            }
        }
        Collections.reverse(result);
        return result.stream().reduce((a, b) -> a + b).get();
    }

    @Override
    public BArea getProvinceAndCityLikeCityName(String cityName) {
        LOGGER.info("get ProvinceAndCity like city Name : {}", cityName);
        if (StringUtils.isBlank(cityName)) {
            LOGGER.info("getProvinceAndCityLikeCityName cityName must not be null");
            return null;
        }
        // 查询城市和省（城市上一级）
        BAreaExample example = new BAreaExample();
        example.createCriteria().andNameLike(cityName + "%").andLevelEqualTo("2");
        List<BArea> citys = bAreaMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(citys)) {
            LOGGER.info("getProvinceAndCityLikeCityName result list is empty");
            return null;
        }
        BArea city = citys.get(0);

        return city;
    }

    @Override
    public BArea selectAreaByCodeAndLevel(String code, String level) {
        LOGGER.info("select barea by code and level params code:{}, level:{}.", code, level);
        BArea bArea = new BArea();
        try {
            BAreaExample example = new BAreaExample();
            if (null != code) {
                example.createCriteria().andCodeEqualTo(code).andLevelEqualTo(level);
                List<BArea> list = this.getBAreaMapper().selectByExample(example);
                if (CollectionUtils.isNotEmpty(list)) {
                    bArea = list.get(0);
                }
            }
        } catch (Exception e) {
            LOGGER.error("select barea by code and level error : {}.", e);
            e.printStackTrace();
        }
        return bArea;
    }

    @Override
    public List<BArea> selectAreaByPinyin() {
        BAreaExample example = new BAreaExample();
        example.createCriteria().andLevelBetween("2", "3");
        return this.getBAreaMapper().selectByExample(example);
    }

    @Override
    public List<BArea> selectCity() throws Exception {
        BAreaExample example = new BAreaExample();
        example.createCriteria().andLevelEqualTo("2");
        return this.getBAreaMapper().selectByExample(example);
    }

    /**
     * 查询省市 城市级别
     */
    @Override
    public Map<String, Object> selectCityRatingList(PageVo page, BAreaCityRatingVo bAreaCityRatingVo) {
        LOGGER.info("select CityRatingList params bAreaCityRatingVo : {}.", JSON.toJSONString(bAreaCityRatingVo));
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            page.setTotalRecord(this.getBAreaViewMapper().getCount(bAreaCityRatingVo));
            List<BAreaCityRatingVo> list = this.getBAreaViewMapper().selectByConditions(page, bAreaCityRatingVo);

            map.put("page", page);
            map.put("cityRatingList", list);
        } catch (Exception e) {
            LOGGER.error("select CityRatingList error : {}.", e);
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 更新省市 城市级别
     */
    @Override
    public Result<String> updateCityRating(BAreaCityRatingVo bAreaCityRatingVo) {
        LOGGER.info("update CityRating params bAreaCityRatingVo : {}.", JSON.toJSONString(bAreaCityRatingVo));
        Result<String> result = new Result<String>(true, null, "更新城市级别完成.");
        if (StringUtils.isBlank(bAreaCityRatingVo.getProCode())) {
            LOGGER.info("update CityRating proCode is not null.");
            result.setSuccess(false);
            result.setMessage("省编码不能为空！");
            return result;
        } else if (StringUtils.isBlank(bAreaCityRatingVo.getCityCode())) {
            LOGGER.info("update CityRating cityCode is not null.");
            result.setSuccess(false);
            result.setMessage("市编码不能为空！");
            return result;
        } else if (StringUtils.isBlank(bAreaCityRatingVo.getCityRating())) {
            LOGGER.info("update CityRating cityRating is not null.");
            result.setSuccess(false);
            result.setMessage("城市级别不能为空！");
            return result;
        }
        try {
            result.setData(this.getBAreaViewMapper().updateByConditions(bAreaCityRatingVo) + "");
            /** BAreaExample example = new BAreaExample();
             example.createCriteria().andParentCodeEqualTo(bAreaCityRatingVo.getCityCode()).andLevelEqualTo("3");
             List<BArea> list = this.getBAreaMapper().selectByExample(example);
             for (BArea bArea : list) {
             logger.info("update CityRating update district params id : {}.", bArea.getCode());
             bArea.setCityRating(bAreaCityRatingVo.getCityRating());
             this.getBAreaMapper().updateByPrimaryKey(bArea);
             } */
            LOGGER.info("update CityRating finish.");
        } catch (Exception e) {
            LOGGER.error("update CityRating error : {}.", e);
            result.setSuccess(false);
            result.setMessage("update CityRating error.");
            e.printStackTrace();
        }
        return result;
    }

    @Override
    public BArea selectProByCityCode(String citycode) {
        BArea proBArea = new BArea();
        try {
            BAreaExample example = new BAreaExample();
            example.createCriteria().andCodeEqualTo(citycode).andLevelEqualTo("2");
            BArea bArea = this.getBAreaMapper().selectByExample(example).get(0);

            String parentCode = bArea.getParentCode();
            BAreaExample example2 = new BAreaExample();
            example2.createCriteria().andCodeEqualTo(parentCode).andLevelEqualTo("1");
            proBArea = this.getBAreaMapper().selectByExample(example2).get(0);
        } catch (Exception e) {
            LOGGER.error("select pro by citycode error : {}.", e);
            e.printStackTrace();
        }
        return proBArea;
    }

    public BigDecimal getCityCoefficientByCode(String code) {
        LOGGER.info("getCityCoefficientByCode param : {}", code);
        if (StringUtils.isBlank(code)) {
            LOGGER.error("getCityCoefficientByCode code is blank");
            throw new IllegalArgumentException("城市code不能为空！");
        }
        BAreaExample example = new BAreaExample();
        example.createCriteria().andCodeEqualTo(code);
        List<BArea> list = bAreaMapper.selectByExample(example);
        if (CollectionUtils.isEmpty(list)) {
            LOGGER.error("getCityCoefficientByCode list is empty");
            throw new BusinessException("获取城市信息失败！");
        }
        String feeCode = "C3";
        BArea area = list.get(0);
        if (null != area && StringUtils.isNotBlank(area.getCityRating())) {
            feeCode = area.getCityRating();
        }
        return this.getBCityFactorService().getVlaueByFeeCode(feeCode);
    }

    @Override
    public int generatePinyin() {
        List<BArea> areas = this.getBAreaMapper().selectByExample(new BAreaExample());
        for (BArea bArea : areas) {
            if (!"1".equals(bArea.getLevel())) {
                String pinyin = getPinYin(bArea.getName());
                bArea.setPinyin(pinyin);
                this.getBAreaMapper().updateByPrimaryKeySelective(bArea);
            }
        }
        return 0;
    }

    public static String getPinYin(String inputString) {
        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
        format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        format.setVCharType(HanyuPinyinVCharType.WITH_U_UNICODE);
        char[] input = inputString.trim().toCharArray();
        StringBuffer output = new StringBuffer("");
        try {
            for (int i = 0; i < input.length; i++) {
                if (Character.toString(input[i]).matches("[\u4E00-\u9FA5]+")) {
                    String[] temp = PinyinHelper.toHanyuPinyinStringArray(input[i], format);
                    output.append(temp[0]);
                } else
                    output.append(Character.toString(input[i]));
            }
        } catch (BadHanyuPinyinOutputFormatCombination e) {
            e.printStackTrace();
        }
        return output.toString();
    }

    public static String getFirstSpell(String chinese) {
        StringBuffer pybf = new StringBuffer();
        char[] arr = chinese.toCharArray();
        HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
        defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] > 128) {
                try {
                    String[] temp = PinyinHelper.toHanyuPinyinStringArray(arr[i], defaultFormat);
                    if (temp != null) {
                        pybf.append(temp[0].charAt(0));
                    }
                } catch (BadHanyuPinyinOutputFormatCombination e) {
                    e.printStackTrace();
                }
            } else {
                pybf.append(arr[i]);
            }
        }
        return pybf.toString().replaceAll("\\W", "").trim();
    }

    @Override
    public int generateFirstSpell() {
        List<BArea> areas = this.getBAreaMapper().selectByExample(new BAreaExample());
        for (BArea bArea : areas) {
            if (!"1".equals(bArea.getLevel())) {
                String pinyin = getFirstSpell(bArea.getName());
                bArea.setInitialWords(pinyin);
                this.getBAreaMapper().updateByPrimaryKeySelective(bArea);
            }
        }
        return 0;
    }

    @Override
    public List<BAreaSearchVo> selectBArea(String code, String params, Boolean isVeneer) throws Exception {
        LOGGER.info("selectBArea params code:{}, params: {}, isVeneer: {}", code, params, isVeneer);
        if (null == isVeneer) {
            isVeneer = false;
        }
        List<BAreaSearchVo> areaSearchVos = new ArrayList<>();
        if (StringUtils.isBlank(code) && StringUtils.isBlank(params)) return areaSearchVos;
        List<BAreaVo> list = this.getBAreaViewMapper().selectBArea(code, params, isVeneer);
        if (CollectionUtils.isNotEmpty(list)) {
            LOGGER.info("selectBArea records : {}", list.size());
            for (BAreaVo areaVo : list) {
                BAreaSearchVo areaSearchVo = new BAreaSearchVo();
                areaSearchVo.setpName(areaVo.getpName());
                areaSearchVo.setCityCode(areaVo.getParentCode());
                areaSearchVo.setCityName(areaVo.getCityName());
                areaSearchVo.setProvinceName(areaVo.getProvinceName());
                areaSearchVo.setProvinceCode(areaVo.getProvinceCode());
                areaSearchVo.setCountyCode(areaVo.getCode());
                areaSearchVo.setCountyName(areaVo.getName());
                areaSearchVos.add(areaSearchVo);
            }
        }
        return areaSearchVos;
    }


    @Override
    public List<BCityVo> selectCounties(String code) {
        return bAreaViewMapper.selectCities(code);
    }

    @Override
    public List<BAreaSearchVo> selectLikename(String provinceName, String cityName, String countyName) {
        LOGGER.info("select Area like name : province:{}, city:{}, county{}", provinceName, cityName, countyName);
        return bAreaViewMapper.selectLikeName(provinceName, cityName, countyName);
    }

    @Override
    public List<BArea> selectBareaByParams(String params) throws Exception {
        LOGGER.info("select barea params: {}", params);
        if ("depart".equals(params)) {
            BAreaExample example = new BAreaExample();
            example.createCriteria().andCodeEqualTo("360000");
            return this.getBAreaMapper().selectByExample(example);
        } else {
            return this.selectProvinceList();
        }
    }

    @Override
    public List<BArea> getIntracityCityList() {

        BAreaExample example = new BAreaExample();
        example.createCriteria().andLevelEqualTo("2").andIsVeneerEqualTo(true);

        return bAreaMapper.selectByExample(example);
    }

    @Override
    public BArea selectParentByChild(String childCode) throws Exception {
        LOGGER.info("selectParentByChild param : {}", childCode);
        if (StringUtils.isBlank(childCode)) {
            LOGGER.error("selectParentByChild param childCode must not be null");
            throw new IllegalArgumentException("子节点编码不能为空");
        }

        List<BArea> bAreas = this.selectAreaByCode(childCode);

        BAreaExample example = new BAreaExample();
        example.createCriteria().andCodeEqualTo(bAreas.get(0).getParentCode());

        List<BArea> list = bAreaMapper.selectByExample(example);
        if (CollectionUtils.isNotEmpty(list)) {
            return list.get(0);
        }

        return null;
    }
}
